package com.thx.common.util;

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
 * 简单哈希算法，支持MD5、SHA-1等算法.
 *
 * @author calonlan
 */
public class SimpleHash {

  private static final int DEFAULT_ITERATIONS = 1;

  private byte[] bytes;//已经加密的字节数组

  private String algorithmName;//加密算法名称，例如MD5、SHA-1等

  private int hashIterations;//加密迭代次数，次数越多安全性越高、速度越慢

  /**
   * hash算法构造器.
   */
  public SimpleHash(String algorithmName, String source, String salt,
                    int hashIterations) throws UnsupportedEncodingException,
      NoSuchAlgorithmException {

    byte[] saltBytes = null;
    if (salt != null && salt.length() > 0) {
      saltBytes = salt.getBytes("UTF-8");
    } else {
      throw new NullPointerException("salt argument cannot be null or empty.");
    }

    byte[] sourceBytes = null;
    if (source != null && source.length() > 0) {
      sourceBytes = source.getBytes("UTF-8");
    } else {
      throw new NullPointerException("source argument cannot be null or empty");
    }
    this.algorithmName = algorithmName;
    this.hashIterations = Math.max(DEFAULT_ITERATIONS, hashIterations);
    this.bytes = hash(sourceBytes, saltBytes);
  }


  /**
   * hash加密.
   */
  protected byte[] hash(byte[] bytes, byte[] salt) throws NoSuchAlgorithmException {
    MessageDigest digest = getDigest();
    if (salt != null) {
      digest.reset();
      //通过salt(盐)更新信息摘要
      digest.update(salt);
    }
    byte[] hashed = digest.digest(bytes);
    int iterations = hashIterations - DEFAULT_ITERATIONS; //already hashed once above
    //iterate remaining number:
    for (int i = 0; i < iterations; i++) {
      digest.reset();
      hashed = digest.digest(hashed);
    }
    return hashed;
  }

  private MessageDigest getDigest() throws NoSuchAlgorithmException {
    try {
      return MessageDigest.getInstance(algorithmName);
    } catch (NoSuchAlgorithmException ex) {
      String msg = "No native '" + algorithmName
          + "' MessageDigest instance available on the current JVM.";
      throw new NoSuchAlgorithmException(msg);
    }
  }

  /**
   * 把加密的字节数组转成16进制的字符串.
   */
  public String toHex() {
    String hexEncoded = Hex.encodeToString(bytes);
    return hexEncoded;
  }

}
